﻿using mozhi.smarterp.Finance.Accounts;
using mozhi.smarterp.Finance.Accounts.Repository;
using mozhi.smarterp.Finance.Accounts.Services;
using mozhi.smarterp.Finance.Basedatas.Repository;
using mozhi.smarterp.Finance.Basedatas.Services;
using mozhi.smarterp.Finance.Enums;
using mozhi.smarterp.Finance.Finances.Repository;
using mozhi.smarterp.Finance.Finances.Services;
using mozhi.smarterp.Finance.Querys;
using mozhi.smarterp.Finance.Reports.Repository;
using Mozhi.Abp.Core.Extensions;
using Mozhi.Abp.Domain.BasicData;
using Mozhi.Abp.Domain.BasicData.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;

namespace mozhi.smarterp.Finance.Reports
{
    public class IncomeStatementReportAppService : FinancialReportAppService, IIncomeStatementReportAppService
    {
        private IFinancialReportItemRepository _financialReportItemRepository;

        public IncomeStatementReportAppService(IAccountRepository accountRepository, IDimensionGroupValueRepository dimensionGroupValueRepository, ICurrencyRepository currencyRepository,
            ISettlementRepository settlementRepository, IAccountBalanceRepository accountBalanceRepository, AccountBalanceManager accountBalanceManager,
            DimensionGroupValueManager dimensionGroupValueManager, IOrganizationRepository organizationRepository, IFinancialReportItemRepository financialReportItemRepository,
            IEndPeriodProcessResultRepository endPeriodProcessResultRepository, IJournalRepository journalRepository, JournalManager journalManager) :
            base(accountRepository, dimensionGroupValueRepository, currencyRepository, settlementRepository,
                accountBalanceRepository, accountBalanceManager, dimensionGroupValueManager, organizationRepository, endPeriodProcessResultRepository, journalRepository, journalManager)
        {
            _financialReportItemRepository = financialReportItemRepository;
        }

        public async Task<List<IncomeStatementReportDto>> GetData(IncomeStatementReportQuery query)
        {
            var result = new List<IncomeStatementReportDto>();

            if (query == null || query.StartPeriod == 0)
                throw new UserFriendlyException("查询参数不能为空，并且开始期间不能为空", "100000");

            query.EndPeriod = query.DateType == 1 ? query.StartPeriod : query.EndPeriod;

            if (query.EndPeriod == 0)
                throw new UserFriendlyException("结束期间不能为空", "100000");

            if (query.StartPeriod.ToLastDayDateTime().Year != query.EndPeriod.ToLastDayDateTime().Year)
                throw new UserFriendlyException("不允许跨年查询", "100000");

            if (query.IsLastYear)
                await ValidateLastPeriodIsClosedAsync(query.StartPeriod, query.EndPeriod);

            //获取当前期的余额(只需要综合本位币数据)
            var balances = await GetAccountBalancesAsync(new ReportQueryBase() { StartPeriod = query.StartPeriod, EndPeriod = query.EndPeriod, IncludeDimension = false, IncludeCurrency = false , 
                IncludeUnApproveJournal=query.IncludeUnApproveJournal });

            if (query.IsLastYear)
            {
                var lastPeriods = GetLastPeriods(query.StartPeriod, query.EndPeriod);

                //上一年同期余额(只需要综合本位币数据)
                var lastYearBalances = await GetAccountBalancesAsync(new ReportQueryBase() { StartPeriod = lastPeriods[0], EndPeriod = lastPeriods[1] , IncludeDimension = false, IncludeCurrency = false });

                if (lastYearBalances != null)
                    balances.AddRange(lastYearBalances);
            }

            result = await HandleIncomeStatement(query, balances);

            return result;
        }


        #region
        private async Task ValidateLastPeriodIsClosedAsync(int startPeriod , int endPeriod)
        {
            var lastPeriods = GetLastPeriods(startPeriod , endPeriod);

            var settlements = await _settlementRepository.FindAsync(new SettlementQuery() { Periods = new List<int>() { lastPeriods[0], lastPeriods[1] }, Closed = true });

            if (!settlements.Exists(x => x.Period == lastPeriods[0]))
                throw new UserFriendlyException($"上一年期间：{lastPeriods[0]}未结账，无法查询", "100000");

            if (!settlements.Exists(x => x.Period == lastPeriods[1]))
                throw new UserFriendlyException($"上一年期间：{lastPeriods[1]}未结账，无法查询", "100000");
        }


        private int[] GetLastPeriods(int startPeriod , int endPeriod)
        {
            var lastStartPeriod = startPeriod.ToLastDayDateTime().AddYears(-1).ToPeriod();

            var lastEndPeriod = endPeriod.ToLastDayDateTime().AddYears(-1).ToPeriod();

            return [lastStartPeriod, lastEndPeriod];
        }


        /// <summary>
        /// 处理利润表数据
        /// </summary>
        /// <param name="filter"></param>
        /// <param name="balances"></param>
        /// <param name="accounts"></param>
        /// <returns></returns>
        public async Task<List<IncomeStatementReportDto>> HandleIncomeStatement(IncomeStatementReportQuery filter, List<AccountBalance> balances)
        {
            //var reportItems = await _financialReportItemRepository.FindAsync(new FinancialReportItemQuery() { ReportType = Enums.FinancialReportType.IncomeStatement });

            //var result = new List<IncomeStatementReportDto>();

            //if (reportItems.Count == 0)
            //    return result;

            //var accounts = await _accountRepository.FindAsync(new AccountQuery());

            //var currentPeriodBalances = balances.Where(x => x.Period >= filter.StartPeriod && x.Period <= filter.EndPeriod).ToList();

            //var maxPeriod = currentPeriodBalances.Max(x => x.Period);

            ////本年累计数永远只取最大期间的余额
            //var currentYearBalances = currentPeriodBalances.Where(x => x.Period == maxPeriod).ToList();

            ////处理期初的本年累计
            //await HandleOpeningCurrentYearBalanceAsync(accounts, currentYearBalances , (await GetOrganizationAsync()));


            //var lastYearPeriods = GetLastPeriods(filter.StartPeriod, filter.EndPeriod);

            ////如果条件是上年数
            //var lastYearBalances = filter.IsLastYear ? balances.Where(x => x.Period >= lastYearPeriods[0] && x.Period <= lastYearPeriods[1]).ToList() : new List<AccountBalance>();

            ////排除结转损益凭证的金额
            //if (filter.IsLastYear)
            //{
            //    //这里做个判断是因为，条件不是上年数的时候，不需要取本年累计金额，所以不需要取年初到当前期间的损益凭证,加快点速度
            //    await ExcludeProfitLossJournal(accounts, filter.StartPeriod, filter.EndPeriod, currentPeriodBalances, filter.IncludeUnApproveJournal);

            //    await ExcludeProfitLossJournal(accounts, lastYearPeriods[0], lastYearPeriods[1], lastYearBalances, false);

            //}
            //else
            //{
            //    //当前年的第一期
            //    var yearFirstPeriod = filter.StartPeriod.ToFirstDayDateTime().Year * 100 + 1;

            //    await ExcludeProfitLossJournal(accounts, yearFirstPeriod, filter.EndPeriod, currentPeriodBalances, filter.IncludeUnApproveJournal);
            //}

            //var reportItemDtos = ObjectMapper.Map<List<FinancialReportItem>, List<FinancialReportItemDto>>(reportItems);


            //foreach (var reportItem in reportItemDtos)
            //{
            //    var reportRow = new IncomeStatementReportDto();

            //    reportRow.ReportItemId = reportItem.Id;
            //    reportRow.ReportItemName = reportItem.Name;
            //    reportRow.Number = reportItem.Number;

            //    //本期数
            //    reportRow.CurrentPeriodAmount = await GetReportItemAmount(1, reportItem, accounts, currentPeriodBalances, reportItemDtos);

            //    //本年累计数
            //    reportRow.CurrentYearAmount = await GetReportItemAmount(2, reportItem, accounts, currentYearBalances, reportItemDtos);

            //    //上年数
            //    reportRow.LastPeriodAmount = await GetReportItemAmount(1, reportItem, accounts, lastYearBalances, reportItemDtos);


            //    result.Add(reportRow);
            //}

            //return result;
            throw new NotImplementedException();
        }


        /// <summary>
        /// 处理启用的科目的本年累计数
        /// 例如借方科目 初始化借方本年累计金额+科目余额表的本年累计借方-科目余额的本年累计贷方
        /// </summary>
        /// <param name="balances"></param>
        /// <returns></returns>
        private async Task<List<AccountBalance>> HandleOpeningCurrentYearBalanceAsync(List<Account> accounts, List<AccountBalance> balances , Organization organization)
        {
            if (balances == null || balances.Count == 0)
                return balances;

            var openingPeriod = organization.ActivatedDate?.ToPeriod();

            if (openingPeriod == null)
                return balances;

            var openingDate = openingPeriod.Value.ToFirstDayDateTime();

            //如果没有启用，或者启用月份是1月，也不进行处理
            if (openingDate.Month == 1)
                return balances;

            //启用年
            var initalizePeriod = openingPeriod.Value.ToPrePeriod();

            var initalizeBalances = await _accountBalanceRepository.FindAsync(new AccountBalanceQuery() { Period = initalizePeriod, IncludeDimension = false, IncludeCurrency = false });

            //没有录入期初余额，也不处理
            if (initalizeBalances.Count == 0)
                return balances;

            var groupByBalances = balances.GroupBy(x => x.Period);

            foreach (IGrouping<int, AccountBalance> info in groupByBalances)
            {
                var period = info.Key;
                var year = period.ToFirstDayDateTime().Year;

                //非启用年，不进行处理
                if (year != openingDate.Year)
                    continue;

                //循环余额，重新计算本年累计
                foreach (var balance in balances)
                {
                    var matchAccount = accounts.FirstOrDefault(x => x.Id == balance.AccountId);

                    //没有科目，处理不了
                    if (matchAccount == null)
                        throw new BusinessException("100000", $"科目：{balance.AccountId}不存在");

                    //匹配到的期初余额
                    var matchInitalizeBalance = initalizeBalances.FirstOrDefault(x => x.AccountId == balance.AccountId);

                    if (matchInitalizeBalance == null)
                        continue;

                    //期初：借方科目取期初的本年累计借方，贷方科目取期初的本年累计贷方（后面代码暂不处理）
                    balance.CurrentYearDebitAmount = matchAccount.Direction == AccountDirectionType.Debit ? balance.CurrentYearDebitAmount
                        : (0 + balance.CurrentYearDebitAmount - matchInitalizeBalance.CurrentYearDebitAmount);

                    balance.CurrentYearCreditAmount = matchAccount.Direction == AccountDirectionType.Credit ? balance.CurrentYearCreditAmount
                        : (0 + balance.CurrentYearCreditAmount - matchInitalizeBalance.CurrentYearCreditAmount);
                }
            }
            return balances;
        }

        #endregion
    }
}
